﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;

namespace RxjhServer.Network
{
	public class TcpClient
	{
		protected IntPtr _pClient = IntPtr.Zero;

		protected IntPtr pListener = IntPtr.Zero;

		protected bool IsCreate;

		private Sdk.OnPrepareConnect _OnPrepareConnect;

		private Sdk.OnConnect _OnConnect;

		private Sdk.OnReceive _OnReceive;

		private Sdk.OnSend _OnSend;

		private Sdk.OnClose _OnClose;

		protected IntPtr pClient
		{
			get
			{
				return this._pClient;
			}
			set
			{
				this._pClient = value;
			}
		}

		public event TcpClientEvent.OnPrepareConnectEventHandler OnPrepareConnect;

		public event TcpClientEvent.OnConnectEventHandler OnConnect;

		public event TcpClientEvent.OnSendEventHandler OnSend;

		public event TcpClientEvent.OnReceiveEventHandler OnReceive;

		public event TcpClientEvent.OnCloseEventHandler OnClose;

		public TcpClient()
		{
			this.CreateListener();
		}

		~TcpClient()
		{
			this.Destroy();
		}

		protected virtual bool CreateListener()
		{
			if (this.IsCreate || this.pListener != IntPtr.Zero || this.pClient != IntPtr.Zero)
			{
				return false;
			}
			this.pListener = Sdk.Create_HP_TcpClientListener();
			if (this.pListener == IntPtr.Zero)
			{
				return false;
			}
			this.pClient = Sdk.Create_HP_TcpClient(this.pListener);
			if (this.pClient == IntPtr.Zero)
			{
				return false;
			}
			this.IsCreate = true;
			return true;
		}

		public virtual void Destroy()
		{
			this.Stop();
			if (this.pClient != IntPtr.Zero)
			{
				Sdk.Destroy_HP_TcpClient(this.pClient);
				this.pClient = IntPtr.Zero;
			}
			if (this.pListener != IntPtr.Zero)
			{
				Sdk.Destroy_HP_TcpClientListener(this.pListener);
				this.pListener = IntPtr.Zero;
			}
			this.IsCreate = false;
		}

		public bool Connetion(string address, ushort port, bool async)
		{
			if (string.IsNullOrEmpty(address))
			{
				throw new Exception("address is null");
			}
			if (port == 0)
			{
				throw new Exception("port is zero");
			}
			if (this.IsStarted)
			{
				return false;
			}
			this.SetCallback();
			return Sdk.HP_Client_Start(this.pClient, address, port, async);
		}

		public bool Connetion(string address, ushort port, string bindAddress, bool async)
		{
			if (string.IsNullOrEmpty(address))
			{
				throw new Exception("address is null");
			}
			if (port == 0)
			{
				throw new Exception("port is zero");
			}
			if (this.IsStarted)
			{
				return false;
			}
			this.SetCallback();
			return Sdk.HP_Client_StartWithBindAddress(this.pClient, address, port, async, bindAddress);
		}

		public bool Stop()
		{
			return this.IsStarted && Sdk.HP_Client_Stop(this.pClient);
		}

		public bool Send(byte[] bytes, int size)
		{
			return Sdk.HP_Client_Send(this.pClient, bytes, size);
		}

		public bool Send(IntPtr bufferPtr, int size)
		{
			return Sdk.HP_Client_Send(this.pClient, bufferPtr, size);
		}

		public bool Send<T>(T obj)
		{
			byte[] array = this.StructureToByte<T>(obj);
			return this.Send(array, array.Length);
		}

		public bool SendBySerializable(object obj)
		{
			byte[] array = this.ObjectToBytes(obj);
			return this.Send(array, array.Length);
		}

		public bool Send(byte[] bytes, int offset, int size)
		{
			return Sdk.HP_Client_SendPart(this.pClient, bytes, size, offset);
		}

		public bool Send(IntPtr bufferPtr, int offset, int size)
		{
			return Sdk.HP_Client_SendPart(this.pClient, bufferPtr, size, offset);
		}

		public bool SendPackets(WSABUF[] buffers, int count)
		{
			return Sdk.HP_Client_SendPackets(this.pClient, buffers, count);
		}

		public bool SendPackets<T>(T[] objects)
		{
			bool result = false;
			WSABUF[] array = new WSABUF[objects.Length];
			IntPtr[] array2 = new IntPtr[array.Length];
			try
			{
				for (int i = 0; i < objects.Length; i++)
				{
					array[i].Length = Marshal.SizeOf(typeof(T));
					array2[i] = Marshal.AllocHGlobal(array[i].Length);
					Marshal.StructureToPtr(objects[i], array2[i], true);
					array[i].Buffer = array2[i];
				}
				result = this.SendPackets(array, array.Length);
			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				for (int j = 0; j < array2.Length; j++)
				{
					if (array2[j] != IntPtr.Zero)
					{
						Marshal.FreeHGlobal(array2[j]);
					}
				}
			}
			return result;
		}

		public bool SendSmallFile(string filePath, ref WSABUF head, ref WSABUF tail)
		{
			return Sdk.HP_TcpClient_SendSmallFile(this.pClient, filePath, ref head, ref tail);
		}

		public bool SendSmallFile(string filePath, byte[] head, byte[] tail)
		{
			IntPtr zero = IntPtr.Zero;
			IntPtr zero2 = IntPtr.Zero;
			WSABUF wSABUF = new WSABUF
			{
				Length = 0,
				Buffer = zero
			};
			WSABUF wSABUF2 = new WSABUF
			{
				Length = 0,
				Buffer = zero2
			};
			if (head != null)
			{
				wSABUF.Length = head.Length;
				wSABUF.Buffer = Marshal.UnsafeAddrOfPinnedArrayElement(head, 0);
			}
			if (tail != null)
			{
				wSABUF.Length = tail.Length;
				wSABUF.Buffer = Marshal.UnsafeAddrOfPinnedArrayElement(tail, 0);
			}
			return this.SendSmallFile(filePath, ref wSABUF, ref wSABUF2);
		}

		public bool SendSmallFile<T1, T2>(string filePath, T1 head, T2 tail)
		{
			byte[] head2 = null;
			if (head != null)
			{
				head2 = this.StructureToByte<T1>(head);
			}
			byte[] tail2 = null;
			if (tail != null)
			{
				tail2 = this.StructureToByte<T2>(tail);
			}
			return this.SendSmallFile(filePath, head2, tail2);
		}

		public SocketError ErrorCode
		{
			get
			{
				return Sdk.HP_Client_GetLastError(this.pClient);
			}
		}

		public string ErrorMessage
		{
			get
			{
				IntPtr ptr = Sdk.HP_Client_GetLastErrorDesc(this.pClient);
				return Marshal.PtrToStringUni(ptr);
			}
		}

		public bool GetPendingDataLength(ref int length)
		{
			return Sdk.HP_Client_GetPendingDataLength(this.pClient, ref length);
		}

		public void SetExtra(object obj)
		{
			IntPtr intPtr = this.GetExtra();
			if (intPtr != IntPtr.Zero)
			{
				Marshal.FreeHGlobal(intPtr);
				intPtr = IntPtr.Zero;
			}
			if (obj != null)
			{
				intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
				Marshal.StructureToPtr(obj, intPtr, false);
			}
			Sdk.HP_Client_SetExtra(this.pClient, intPtr);
		}

		public IntPtr GetExtra()
		{
			return Sdk.HP_Client_GetExtra(this.pClient);
		}

		public bool GetListenAddress(ref string ip, ref ushort port)
		{
			int capacity = 40;
			StringBuilder stringBuilder = new StringBuilder(capacity);
			bool flag = Sdk.HP_Client_GetLocalAddress(this.pClient, stringBuilder, ref capacity, ref port);
			if (flag)
			{
				ip = stringBuilder.ToString();
			}
			return flag;
		}

		public bool IsStarted
		{
			get
			{
				return !(this.pClient == IntPtr.Zero) && Sdk.HP_Client_HasStarted(this.pClient);
			}
		}

		public ServiceState State
		{
			get
			{
				return Sdk.HP_Client_GetState(this.pClient);
			}
		}

		public IntPtr ConnectionId
		{
			get
			{
				return Sdk.HP_Client_GetConnectionID(this.pClient);
			}
		}

		public uint FreeBufferPoolSize
		{
			get
			{
				return Sdk.HP_Client_GetFreeBufferPoolSize(this.pClient);
			}
			set
			{
				Sdk.HP_Client_SetFreeBufferPoolSize(this.pClient, value);
			}
		}

		public uint FreeBufferPoolHold
		{
			get
			{
				return Sdk.HP_Client_GetFreeBufferPoolHold(this.pClient);
			}
			set
			{
				Sdk.HP_Client_SetFreeBufferPoolHold(this.pClient, value);
			}
		}

		public uint SocketBufferSize
		{
			get
			{
				return Sdk.HP_TcpClient_GetSocketBufferSize(this.pClient);
			}
			set
			{
				Sdk.HP_TcpClient_SetSocketBufferSize(this.pClient, value);
			}
		}

		public uint KeepAliveTime
		{
			get
			{
				return Sdk.HP_TcpClient_GetKeepAliveTime(this.pClient);
			}
			set
			{
				Sdk.HP_TcpClient_SetKeepAliveTime(this.pClient, value);
			}
		}

		public uint KeepAliveInterval
		{
			get
			{
				return Sdk.HP_TcpClient_GetKeepAliveInterval(this.pClient);
			}
			set
			{
				Sdk.HP_TcpClient_SetKeepAliveInterval(this.pClient, value);
			}
		}

		public string GetSocketErrorDesc(SocketError code)
		{
			IntPtr ptr = Sdk.HP_GetSocketErrorDesc(code);
			return Marshal.PtrToStringUni(ptr);
		}

		protected virtual void SetCallback()
		{
			this._OnPrepareConnect = new Sdk.OnPrepareConnect(this.SDK_OnPrepareConnect);
			this._OnConnect = new Sdk.OnConnect(this.SDK_OnConnect);
			this._OnSend = new Sdk.OnSend(this.SDK_OnSend);
			this._OnReceive = new Sdk.OnReceive(this.SDK_OnReceive);
			this._OnClose = new Sdk.OnClose(this.SDK_OnClose);
			Sdk.HP_Set_FN_Client_OnPrepareConnect(this.pListener, this._OnPrepareConnect);
			Sdk.HP_Set_FN_Client_OnConnect(this.pListener, this._OnConnect);
			Sdk.HP_Set_FN_Client_OnSend(this.pListener, this._OnSend);
			Sdk.HP_Set_FN_Client_OnReceive(this.pListener, this._OnReceive);
			Sdk.HP_Set_FN_Client_OnClose(this.pListener, this._OnClose);
		}

		protected HandleResult SDK_OnPrepareConnect(IntPtr pClient, uint socket)
		{
			if (this.OnPrepareConnect != null)
			{
				return this.OnPrepareConnect(this, socket);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnConnect(IntPtr pClient)
		{
			if (this.OnConnect != null)
			{
				return this.OnConnect(this);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnSend(IntPtr pClient, IntPtr pData, int length)
		{
			if (this.OnSend != null)
			{
				byte[] array = new byte[length];
				Marshal.Copy(pData, array, 0, length);
				return this.OnSend(this, array);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnReceive(IntPtr pClient, IntPtr pData, int length)
		{
			if (this.OnReceive != null)
			{
				byte[] array = new byte[length];
				Marshal.Copy(pData, array, 0, length);
				return this.OnReceive(this, array);
			}
			return HandleResult.Ignore;
		}

		protected HandleResult SDK_OnClose(IntPtr pClient, SocketOperation enOperation, int errorCode)
		{
			if (this.OnClose != null)
			{
				return this.OnClose(this, enOperation, errorCode);
			}
			return HandleResult.Ignore;
		}

		public int SYSGetLastError()
		{
			return Sdk.SYS_GetLastError();
		}

		public int SYSWSAGetLastError()
		{
			return Sdk.SYS_WSAGetLastError();
		}

		public int SYS_SetSocketOption(IntPtr sock, int level, int name, IntPtr val, int len)
		{
			return Sdk.SYS_SetSocketOption(sock, level, name, val, len);
		}

		public int SYSGetSocketOption(IntPtr sock, int level, int name, IntPtr val, ref int len)
		{
			return Sdk.SYS_GetSocketOption(sock, level, name, val, ref len);
		}

		public int SYSIoctlSocket(IntPtr sock, long cmd, IntPtr arg)
		{
			return Sdk.SYS_IoctlSocket(sock, cmd, arg);
		}

		public int SYS_WSAIoctl(IntPtr sock, uint dwIoControlCode, IntPtr lpvInBuffer, uint cbInBuffer, IntPtr lpvOutBuffer, uint cbOutBuffer, uint lpcbBytesReturned)
		{
			return Sdk.SYS_WSAIoctl(sock, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned);
		}

		public byte[] StructureToByte<T>(T structure)
		{
			int num = Marshal.SizeOf(typeof(T));
			byte[] array = new byte[num];
			IntPtr intPtr = Marshal.AllocHGlobal(num);
			try
			{
				Marshal.StructureToPtr(structure, intPtr, true);
				Marshal.Copy(intPtr, array, 0, num);
			}
			finally
			{
				Marshal.FreeHGlobal(intPtr);
			}
			return array;
		}

		public T ByteToStructure<T>(byte[] dataBuffer)
		{
			object obj = null;
			int num = Marshal.SizeOf(typeof(T));
			IntPtr intPtr = Marshal.AllocHGlobal(num);
			try
			{
				Marshal.Copy(dataBuffer, 0, intPtr, num);
				obj = Marshal.PtrToStructure(intPtr, typeof(T));
			}
			finally
			{
				Marshal.FreeHGlobal(intPtr);
			}
			return (T)((object)obj);
		}

		public byte[] ObjectToBytes(object obj)
		{
			byte[] buffer;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				IFormatter formatter = new BinaryFormatter();
				formatter.Serialize(memoryStream, obj);
				buffer = memoryStream.GetBuffer();
			}
			return buffer;
		}

		public object BytesToObject(byte[] bytes)
		{
			object result;
			using (MemoryStream memoryStream = new MemoryStream(bytes))
			{
				IFormatter formatter = new BinaryFormatter();
				result = formatter.Deserialize(memoryStream);
			}
			return result;
		}

		public T BytesToStruct<T>(byte[] bytes)
		{
			Type typeFromHandle = typeof(T);
			int num = Marshal.SizeOf(typeFromHandle);
			IntPtr intPtr = Marshal.AllocHGlobal(num);
			T result;
			try
			{
				Marshal.Copy(bytes, 0, intPtr, num);
				result = (T)((object)Marshal.PtrToStructure(intPtr, typeFromHandle));
			}
			finally
			{
				Marshal.FreeHGlobal(intPtr);
			}
			return result;
		}
	}
}
